from base_method import *
from get_service_data import *
from get_instance_data import *
from get_latest_info import *
import json
from es_config import get_now_date
import threading
lock = threading.Lock()
time1 = get_now_date()

def clustering(num):
    """
    决策算法模块
    :return:
    """
    # 从es库里获取数据
    ahead_hour = 3  # 前多少个小时
    df, keys = get_services(ahead_hour, time1)
    # 获取当前服务信息
    test_df = get_service_minutes(keys, 1, time1)
    # print(test_df)
    service_length = len(test_df)
    # print('现有服务的个数：', service_length)

    df = pd.concat([df, test_df])
    outcome = {}
    for i in range(1, num+1):
        outcome['类型'+str(i)] = []
    df = df[df['service_cpm'] != 0].values[:, 2:]
    for col in range(df.shape[1]):
        min_val = min(df[:, col])
        max_val = max(df[:, col])
        df[:, col] = (df[:, col] - min_val) / (max_val - min_val)

    # k-means方法
    kmeans = KMeans(n_clusters=num).fit(df)
    labels = list(kmeans.labels_)
    y = [0 for _ in range(len(labels))]
    l = list(set(labels))
    l.sort(key=labels.index)
    # l = list(np.unique(labels))
    for i in range(len(labels)):
        y[i] = l.index(labels[i])
    # print(kmeans.cluster_centers_)

    # DBSCAN方法
    # dbscan = DBSCAN().fit(df)
    # y = dbscan.labels_

    # birch方法
    # birch = Birch().fit(df)
    # y = birch.labels_

    # 使用TSNE进行可视化
    # tsne = manifold.TSNE(n_components=2, init='pca')
    # X_tsne = tsne.fit_transform(df)
    # x_min, x_max = X_tsne.min(0), X_tsne.max(0)
    # X_norm = (X_tsne - x_min) / (x_max - x_min)  # 归一化
    # for i in range(X_norm.shape[0]):
    #     plt.text(X_norm[i, 0], X_norm[i, 1], str(y[i]), color=plt.cm.Set1(y[i]),
    #              fontdict={'weight': 'bold', 'size': 9})
    # plt.savefig('figure\\cluster.png')
    # plt.show()

    # 返回服务的属性和服务所属类别
    for i in range(1, service_length+1):
        service_info = {'serviceName': test_df['service_id'].values[-i],
                        'reposeTime': test_df['service_resp_time'].values[-i],
                        'successRate': test_df['service_sla'].values[-i],
                        'requestNum': test_df['service_cpm'].values[-i]}
        outcome['类型'+str(y[-i]+1)].append(service_info)
    return outcome


def LSTM_train(serviceName, Instance):
    """
    LSTM模型训练，20预测5
    :return:
    """
    if not Instance:
        df, keys = get_services(24, time1)
        df = df[df['service_id'] == serviceName].iloc[:, 1:]
    else:
        df = get_instances(24, time1)
        df = df[df['instance_id'] == Instance].iloc[:, 1:]

    metrics = df.columns.tolist()

    # 针对每一个指标进行LSTM模型的训练和存储
    input_length = 20
    output_length = 5
    for index, metric in enumerate(metrics):
        data = df[metric].values
        # 如果出现某个指标数值全都一样，不用训练LSTM
        if len(set(data)) == 1:
            continue
        train_X, train_Y, valid_X, valid_Y = pre_train(data, input_length, output_length)
        model = lstm_model(input_length, output_length)
        model_check = ModelCheckpoint('./model.h5', monitor='val_loss', verbose=1, save_best_only=True
                                      , mode='auto', period=1)
        history = model.fit(train_X, train_Y, validation_data=(valid_X, valid_Y), batch_size=64,
                            epochs=100, callbacks=[model_check])
        if not Instance:
            save_path = 'LSTM_models\\'+str(serviceName)
        else:
            save_path = os.path.join('LSTM_models', str(serviceName), str(Instance))
        model_name = str(metric)+'.h5'
        if not os.path.exists(save_path):
            os.makedirs(save_path)
        plot_results(history, int(len(metrics)/2)+1, index+1)
        plt.figure(1)


        lock.acquire()
        model.save(os.path.join(save_path, model_name))
        lock.release()
    plt.show()


def LSTM_forecast(serviceName, Instance):
    """
    用LSTM模型进行预测
    :param serviceName: 服务名称
    :param Instance:  实例名称
    :return:
    """
    root_path = 'data'
    input_length = 20
    output_length = 5
    # 获取服务或实例的数据，前20个点

    if not Instance:
        # filename = 'service_info.csv'
        # raw_data = pd.read_csv(os.path.join(root_path, filename), index_col=False)
        # df = pd.DataFrame(raw_data)
        df = get_service_minutes(set(serviceName), 20, time1)
        df = df[df['service_id'] == serviceName].iloc[:, 1:]
        print(df)

    else:
        # filename = 'instance_info.csv'
        # raw_data = pd.read_csv(os.path.join(root_path, filename), index_col=False)
        # df = pd.DataFrame(raw_data)
        df = get_instance_minutes(20, time1)
        df = df[df['instance_id'] == Instance].iloc[:, 2:]

    metrics = df.columns.tolist()
    outcome = {}
    # 获取当前时间以及之后的5分钟
    # time1 = datetime.datetime.now() + datetime.timedelta(hours=8)

    next_times = []
    for i in range(1, 6):
        offset = datetime.timedelta(minutes=i)
        next_times.append((time1 + offset).strftime('%H:%M'))
    # 针对每个metric，加载训练好的模型，进行预测。
    for metric in metrics:
        print(df)
        raw_data = df[metric].values
        print(raw_data)
        scaler = MinMaxScaler(feature_range=(0, 1))
        data = np.array(raw_data)
        data = np.reshape(data, (len(data), 1))
        data = scaler.fit_transform(data)
        testX = np.reshape(data, (1, input_length, 1))
        if not Instance:
            save_path = 'LSTM_models\\'+str(serviceName)
        else:
            save_path = os.path.join('LSTM_models', str(serviceName), str(Instance))
        # 如果该指标的值一直没变，则没有训练好的LSTM模型，直接输出一样的值就行
        if not os.path.exists(os.path.join(save_path, str(metric)+'.h5')) or len(set(raw_data)) == 1:
            predicted = [raw_data[0] for _ in range(output_length)]
        else:
            lock.acquire()
            model = load_model(os.path.join(save_path, str(metric)+'.h5'))
            lock.release()
            predicted = model.predict(testX)
            predicted = scaler.inverse_transform(predicted)
        outcome[metric] = [next_times, predicted]
    # outcome = json.dumps(outcome, ensure_ascii=True)
    return outcome


def get_service__info():
    """
    获取所有服务的名字
    :return:
    """
    services, _ = get_service_instance_dict(time1)
    return services

def get_service_instance_info():

    services, mapping = get_service_instance_dict(time1)
    return mapping


def get_instance_info(serviceName):
    """
    获取对应服务的实例名字
    :return:
    """
    instances = serviceName_to_instances(serviceName, time1)
    return instances


def localize_data(service_names):
    """
    本地化待预测的时序
    :param service_names: 所有服务的名称
    :return:
    """
    get_service_minutes(service_names, 20, time1)
    get_instance_minutes(20, time1)


if __name__ == '__main__':
    service_name = 'test2'
    instance_name = None
    # LSTM_train(service_name, instance_name)
    res = LSTM_forecast(service_name, instance_name)
    print(res)
    # print(get_service_instance_info(time1))

